package gcontent.launch;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import gcontent.config.Configure;
import gcontent.config.error.ConfigEx;
import gcontent.entities.Content;
import gcontent.entities.content.error.ContentEx;
import gcontent.record.Record;
import gcontent.record.db.RecordDB;
import gcontent.record.error.RecordEx;
import gcontent.utils.ConvertUtils;

public class HasherThread extends Thread {
	
	public static final String HASHER_ALGO = "SHA1";
	public static final int WAIT_HASH = 10000;
	
	private RecordDB record_data;
	private MessageDigest mdigest;
	
	private static Logger log = Logger.getLogger(HasherThread.class);
	
	public HasherThread() throws ConfigEx, RecordEx, IllegalAccessException, InstantiationException, ClassNotFoundException, SQLException, NoSuchAlgorithmException 
	{
		Record record;
		
		record = Configure.getGlobalRecord();
		if(record == null)
			throw new RecordEx("not exist Record!");
		
		if(!(record instanceof RecordDB))
			throw new RecordEx("only RecordDB supported!");

		this.record_data = (RecordDB)record.getInstance();			
		this.record_data.connect();	
		this.mdigest = MessageDigest.getInstance(HasherThread.HASHER_ALGO);
	}
	
	private Object UpdateHash(String type_content, Content content) throws ContentEx, RecordEx 
	{
		byte[] hash;
		String str_hash;
		
		hash = this.mdigest.digest(content.getBody());
		str_hash = ConvertUtils.getHexString(hash);
		
		if(log.isDebugEnabled())
			log.debug("=> content \"" + type_content + "\", id = \"" + content.getId() + "\", hash = " + str_hash);

		return (Integer)this.record_data.execProc("PROC_UpdateBodyHash", content.getId(), type_content, str_hash);
	}
	
	private String getTypeContent(int i) throws ContentEx, RecordEx
	{
		return (String)this.record_data.execProc("PROC_GetTypeContent", i);
	}
	
	private ArrayList<Content> getNextUnHashedContent(String type_content) throws ContentEx, RecordEx
	{		
		return (ArrayList<Content>)this.record_data.getObject("PROC_GetNextUnHashedContent", type_content);
	}
	
	public int doHash() throws ContentEx, RecordEx
	{
		String type_content;
		ArrayList<Content> content_list;
		int n_hashed;
		
		n_hashed = 0;
		for(int i = 0; (type_content = getTypeContent(i)) != null; i++) {			
			while((content_list = getNextUnHashedContent(type_content)).size() > 0) {
				for(int n = 0; n < content_list.size(); n++) {
					UpdateHash(type_content, content_list.get(n));
					
					n_hashed++;

				}
			}
			
			this.record_data.flush();
		}
		
		return n_hashed;
	}

	public void run()
	{		
		try { 
			log.info("=> running hasher thread :)");
			
			do {
				int n_hashed;
				
				log.info("=> do hashing.....");
				
				n_hashed = doHash();
				
				log.info("=> total hashed contents " + n_hashed);
				log.info("=> sleeping hashing process for " + HasherThread.WAIT_HASH + " ms.");
				
				Thread.sleep(HasherThread.WAIT_HASH);
			} while(true);
			
		} catch(InterruptedException ex) {
			log.info("=> hasher thread finished");
		} catch(Exception ex) {
 			ex.printStackTrace();
		} finally {
			 try { this.record_data.restore(); } catch(RecordEx ex) { ex.printStackTrace(); }
		}
	}
}
